#ifndef WEBSOCKET_H
#define WEBSOCKET_H

#include "base64.h"
#include "sha1.h"
#include <string.h>
#include <stdint.h>
#define WS_CONTINUE 0x0
#define WS_TEXT 0x1
#define WS_BINARY 0x2
#define WS_CLOSE 0x8
#define WS_PING 0x9
#define WS_PONG 0xA
#define WS_FIN 0x80
#define WS_HAVE_MASK 0x80
#define WS_CLOSE_NRM

#define WS_CLIENT_KEY_LEN 24
#define WS_SERVER_KEY_LEN 28
#define WS_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
#define WS_GUID_LEN 36
inline char * ws_frame_data(char frame[]){
    switch((unsigned char)frame[1]){
        case 0xFE:
            return frame + 8;
        case 0xFF:
            return frame + 14;
        case 0x7E:
            return frame + 4;
        case 0x7F:
            return frame + 10;
        default:
            return (frame + 2 + ((frame[1]&0x80)?4:0));
    }
}
inline size_t ws_frame_len(char frame[]){
    uint64_t len = 0;
#define SHF_(x,y) ((x)<<=8, (x)+=(unsigned char)(y))
    switch(frame[1] & 0x7F){
        case 0x7F:
            SHF_(len, frame[2]);
            SHF_(len, frame[3]);
            SHF_(len, frame[4]);
            SHF_(len, frame[5]);
            SHF_(len, frame[6]);
            SHF_(len, frame[7]);
            SHF_(len, frame[8]);
            SHF_(len, frame[9]);
            return (len <= SIZE_MAX)?
                (size_t)len : 0;
        case 0x7E:
            SHF_(len, frame[2]);
            SHF_(len, frame[3]);
            return (size_t)len;
        default:
            return (size_t)(frame[1] & 0x7F);
    }
#undef SHF_
} 
inline void ws_unmask(unsigned char *mask, unsigned char *data, size_t len){
    for(int n = len; len--;)
        data[n] = data[n] ^ mask[n & 3];
}
size_t ws_handshake_request(char[], char[], size_t);
int ws_header_get(char[], size_t, char[], char[]);
size_t ws_handshake_response(char[], char[], size_t);
size_t ws_framing(char[], size_t, uint32_t, unsigned int);
size_t ws_write(char[], size_t, char[], size_t);
size_t ws_read(char[], size_t, int*);
#endif
